package trade.axht.control;

import java.io.IOException;
import java.io.Writer;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;

import trade.axht.entity.User;

@RequestMapping("/springmvc")
@Controller
//@SessionAttributes(value={"user"},types={String.class})
public class Handler {
	private static String SUCCESS="success";
	
	@RequestMapping("/test")
	public String testRequetMapping() {
		System.out.println("testRequestMapping");
		return SUCCESS;
	}
	/**
	 * 使用method属性来指定请求方式
	 * @return
	 */
	@RequestMapping(value="/testMethod",method=RequestMethod.POST)
	public String testMethod(){
		System.out.println("testMethod");
		return SUCCESS;
	}
	
	/**
	 * 可以使用params和headers来更加精确的映射请求.params和headers支持简单的表达式
	 * @return
	 */
	@RequestMapping(value="/testParamsAndHeaders",params={"username","age!=10"})
	public String testParamsAndHeaders(){
		System.out.println("testParamsAndHeaders");
		return SUCCESS;
	
	}
	
	@RequestMapping("/testPathVariable/{id}")
	public String testPathVariable(@PathVariable("id") Integer id){
		System.out.println("testPathVariable: "+id);
		return SUCCESS;
	}
	
	/**
	 * Restful 风格的URL.以CRUD为例：新增：/order POST
	 * 修改：/order/1 PUT update?id=1
	 * 获取： /order/1 GET get?id=1
	 * 删除： /order/1 DELETE delete?id=1
	 * 如何发送PUT请求和DELETE请求？
	 * 1需要配置HiddenHttpMethodFilter
	 * 2需要发送POST请求
	 * 3需要在发送POST请求时携带一个name="_method"的隐藏域，值为DELETE或PUT
	 *  
	 */
	/**
	 * 更新操作
	 * @param id
	 * @return
	 */
	@RequestMapping(value="/testRest/{id}",method=RequestMethod.PUT)
	public String testRestPut(@PathVariable Integer id){
		System.out.println("testRest Put: "+id);
		return SUCCESS;
	}
	/**
	 * 删除操作
	 * @param id
	 * @return
	 */
	@RequestMapping(value="/testRest/{id}",method=RequestMethod.DELETE)
	public String testRestDelete(@PathVariable Integer id){
		System.out.println("testRest Delete: "+id);
		return SUCCESS;
	}
	
	@RequestMapping(value="/testRest",method=RequestMethod.POST)
	public String testRestPost(){
		System.out.println("testRest Post");
		return SUCCESS;
	}
	
	@RequestMapping(value="/testRest/{id}",method=RequestMethod.GET)
	public String testRestGet(@PathVariable Integer id){
		System.out.println("testRest Get: "+id);
		return SUCCESS;
	}
	
	/**
	 * @RequestParam 来映射请求参数，value值即为请求参数的名
	 * required 表示该参数是否必须
	 * defaultValue表示请求参数的默认值 
	 */
	@RequestMapping("/testRequestParam")
	public String testRequestParam(@RequestParam(value="id",required=false,defaultValue="123") Integer id){
		System.out.println("testRequestParam:"+id);
		return SUCCESS;
	}
	/**
	 * 映射请求头信息用法
	 */
	@RequestMapping("/testRequestHeader")
	public String testRequestHeader(@RequestHeader(value="Accept-Language") String al){
		if(al.contains("zh-CN")) System.out.println("中文语言环境");
		System.out.println("testRequestHeader,Accept-Language:"+al);
		return SUCCESS;
	}
	
	/**
	 * 映射一个Cookie值。属性同@RequestParam
	 */
	@RequestMapping("/testCookieValue")
	public String testCookieValue(@CookieValue("JSESSIONID") String sessionId){
		System.out.println("testCookieValue:sessionId: "+sessionId);
		return SUCCESS;
	}
	
	/**
	 * Spring MVC会按请求参数名和POJO属性名进行自动匹配，自动为该对象填充属性值。
	 * 
	 */
	@RequestMapping("/testPOJO")
	public String testPojo(User user){
		System.out.println("testPojo: "+user);
		return SUCCESS;
	}
	
	/**
	 * 可以使用Servlet原生的API作为目标方法的参数 具体支持以下类型
	 * HttpServletRequest
	 * HttpServletResponse
	 * HttpSession
	 * java.security.Principal
	 * Locale InputStream
	 * OutputStream
	 * Reader
	 * Writer
	 * @throws IOException 
	 * 
	 * 
	 */
	@RequestMapping("/testServletAPI")
	public void testServletAPI(HttpServletRequest request,HttpServletResponse response,Writer out) throws IOException{
		System.out.println("testServletAPI, "+request+", "+response);
		out.write("hello springmvc");
	}
	
	/**
	 * 目标方法的返回值可以是ModelAndView类型
	 * 其中可以包含视图和模型信息
	 * SpringMVC会把ModelAndView的model中数据放入到reqeust域对象中
	 * 
	 */
	@RequestMapping("/testModelAndView")
	public ModelAndView testModelAndView(){
		String viewName=SUCCESS;
		ModelAndView modelAndView=new ModelAndView(viewName);
		//添加模型数据到ModelAndView中
		modelAndView.addObject("time",new Date());
		return modelAndView;
	}
	 //通过配合@ResponseBody来将内容或者对象作为HTTP响应正文返回（适合做即时校验）；  
    @RequestMapping(value = "/valid", method = RequestMethod.GET)  
    @ResponseBody  
    public String valid(@RequestParam(value = "userId", required = false) Integer userId,  
            @RequestParam(value = "name") String name) {  
        return String.valueOf(true);  
    }
    /**
     * 目标方法可以添加Map类型（实际上也可以是Model类型或ModelMap类型)的参数
     
     */
    @RequestMapping("/testMap")
	public String testMap(Map<String,Object> map){
		System.out.println(map.getClass().getName());
		map.put("names", Arrays.asList("Tom","Jerry","Mike"));
		return SUCCESS;
	}
    
    /**
     * @SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外（实际上使用的是value属性值）,
     * 还可以通过模型属性的对象类型指定指定哪些模型属性需要放到会话中（实际上使用的是types属性值）
     * 注意：该注解只能放在类的上面，而不能修饰方法
     */
    @RequestMapping("/testSessionAttributes")
    public String testSessionAttributes(Map<String, Object> map){
    	User user=new User("Tom","123456","Lixianshengchao@Outlook.com",15);
    	map.put("user", user);
    	map.put("school", "atguigu");
    	return SUCCESS;
    }
  /*  
    @ModelAttribute
    public void getUser(@RequestParam(value="id",required=false) Integer id,
    	Map<String, Object> map){
    	System.out.println("modelAttribute method");
    	if(id!=null){
    	//模拟从数据库中获取对象
    		User user=new User(1,"Tom","123456","tom@atguigu.com",12);
    		System.out.println("从数据库中获取一个对象："+user);
    		map.put("user", user);
    	}
    }*/
    /**
     * 标记ModelAttribute,相当于拦截器。调用方法时，会先把请求转发到标记ModelAttribute的方法，之后再调用具体的方法。
     * 使用ModelAttribute的入参会先从数据模型区域中查找指定的对象，若没法找到，则会去判断该类是否标有SessionAttributes.
     * 如何该类标有SessionAttributes，则从会话中查找指定对象，若没有则抛出异常。
     * 如果该类没有标有SessionAttributes，则创建一个新的对象。
     * 最后，将前端传过来的参数覆盖从数据模型或从会话中取出的对象。
     * @param user
     * @return
     */
    @RequestMapping("/testModelAttribute")
    public String testModelAttribute(@ModelAttribute("user") User user,Map<String, Object> map){
    	System.out.println("修改: "+user);
    	map.put("user",user);
    	return SUCCESS;
    }
    
    @RequestMapping("/testView")
    public String testView(){
    	System.out.println("testView");
    	return "helloView";
    }
    
    @RequestMapping("/testRedireact")
    public String testRedireact(){
    	System.out.println("testRedirect");
    	return "redirect:/index.jsp";
    }
    
    

}
